package com.dream21th.common.utils;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Objects;


public class RSAUtil {
    /**
     * 加密算法RSA
     */
    public static final String ALGORITHM = "RSA";

    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;

    private static final String PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhI+bECQxE4/ZIZkvJDduELMS8\n" +
            "UEtdG10xmiqIxatJ3ZcjDEjuwQOB+y9rGQmSDtESuM53vETnU0ZoMmdSc4PqAJrB\n" +
            "rQexZwyA67mERspVYheGEpFSf5bZW23PNw4yFutUy1V4Cnx39z8dzvKxcxx3eiOm\n" +
            "WnE2LrfVHqsn28M0GwIDAQAB";

    private static final String PRIVATE_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEj5sQJDETj9khm\n" +
            "S8kN24QsxLxQS10bXTGaKojFq0ndlyMMSO7BA4H7L2sZCZIO0RK4zne8ROdTRmgy\n" +
            "Z1Jzg+oAmsGtB7FnDIDruYRGylViF4YSkVJ/ltlbbc83DjIW61TLVXgKfHf3Px3O\n" +
            "8rFzHHd6I6ZacTYut9UeqyfbwzQbAgMBAAECgYEA0q83F4JkEd/GLFBWYUpvf0wp\n" +
            "uxPkwreFyZI8dYuNVG1iLvEjGxJShwOZhz6B30WwTzXUOOZdEKC0RXPNjrH84W9m\n" +
            "f7f20GyESp6tn6GOxTqyBNJycFHe+KcPxPrF8BhPga3IsTs3nqnNnzsCYzGxoJw2\n" +
            "l5DGQYYyrANgXWmtDIECQQD7of/I2QSoiej8mMjjfgpTvcvUI1FoljEG3FpD/hSI\n" +
            "Qi2dRF4CF17TSbFDbENhmFh4qhbrxt+fcDVEApzj/7NBAkEA5QwyOLUzFNJIYMP2\n" +
            "jWbN8ds3tuVxHJ2cGHl64gdCIoNLA6nk8yP1zuZQL96UfMxUWC4+9/5PNhBJPCU6\n" +
            "MUt8WwJBAOtJr0K+qfxt9805j54oXL+w2Majv5tr1Kv1nvG0wr4mI0DKjJyn/aLT\n" +
            "ZU0GDntTWGZ7pLMSYkdTRHszdkA6+AECQE005jzdP2G2XDVZ+OLDE4qB9W7OOmmF\n" +
            "6xcI49YK0k0l6oRKoWUf6vyZ/8+S/IRwr8GlnQ4lB/hWVwlSFyKEql8CQQCyx7x9\n" +
            "QC5f2e5xtuzkYH8gAUgQLylV7wyoIsbZsBt3KRpiTyXHnoT5Kl4eTk011Khd3QPh\n" +
            "C437MsYYZdJvQy12";


    public static PublicKey getPublicKey(String key) throws Exception {
        byte[] keyBytes = org.apache.commons.codec.binary.Base64.decodeBase64(key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes = org.apache.commons.codec.binary.Base64.decodeBase64(key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }


    public static String encryptByPrivateKey(String data) throws Exception{
        if(Objects.isNull(data)){
            return data;
        }
        PrivateKey generatePrivate = getPrivateKey(PRIVATE_KEY);
        Cipher ci = Cipher.getInstance(ALGORITHM);
        ci.init(Cipher.ENCRYPT_MODE, generatePrivate);
        byte[] bytes = data.getBytes("UTF-8");
        int inputLen = bytes.length;
        int offLen = 0;//偏移量
        int i = 0;
        try(ByteArrayOutputStream bops = new ByteArrayOutputStream()){
            while(inputLen - offLen > 0){
                byte [] cache;
                if(inputLen - offLen > 117){
                    cache = ci.doFinal(bytes, offLen,117);
                }else{
                    cache = ci.doFinal(bytes, offLen,inputLen - offLen);
                }
                bops.write(cache);
                i++;
                offLen = 117 * i;
            }
            byte[] encryptedData = bops.toByteArray();
            String encodeToString = Base64.getEncoder().encodeToString(encryptedData);
            return encodeToString;
        }
    }

    public static String encryptByPublicKey(String data) throws Exception{
        if(Objects.isNull(data)){
            return data;
        }
        PublicKey generatePublic = getPublicKey(PUB_KEY);
        Cipher ci = Cipher.getInstance(ALGORITHM);
        ci.init(Cipher.ENCRYPT_MODE, generatePublic);
        byte[] bytes = data.getBytes("UTF-8");
        int inputLen = bytes.length;
        int offLen = 0;//偏移量
        int i = 0;
        try(ByteArrayOutputStream bops = new ByteArrayOutputStream()){
            while(inputLen - offLen > 0){
                byte [] cache;
                if(inputLen - offLen > 117){
                    cache = ci.doFinal(bytes, offLen,117);
                }else{
                    cache = ci.doFinal(bytes, offLen,inputLen - offLen);
                }
                bops.write(cache);
                i++;
                offLen = 117 * i;
            }
            byte[] encryptedData = bops.toByteArray();
            String encodeToString = Base64.getEncoder().encodeToString(encryptedData);
            return encodeToString;
        }
    }


    public static String decryptByPublicKey(String data) throws Exception{
        if(Objects.isNull(data)){
            return data;
        }
        PublicKey generatePublic = getPublicKey(PUB_KEY);
        Cipher ci = Cipher.getInstance(ALGORITHM);
        ci.init(Cipher.DECRYPT_MODE,generatePublic);
        byte[] bytes = Base64.getDecoder().decode(data);
        int inputLen = bytes.length;
        int offLen = 0;
        int i = 0;
        try(ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()){
            while(inputLen - offLen > 0){
                byte[] cache;
                if(inputLen - offLen > 128){
                    cache = ci.doFinal(bytes,offLen,128);
                }else{
                    cache = ci.doFinal(bytes,offLen,inputLen - offLen);
                }
                byteArrayOutputStream.write(cache);
                i++;
                offLen = 128 * i;
            }
            byteArrayOutputStream.close();
            byte[] byteArray = byteArrayOutputStream.toByteArray();
            return new String(byteArray);
        }
    }

    public static String decryptByPrivateKey(String data) throws Exception{
        if(Objects.isNull(data)){
            return data;
        }
        PrivateKey generatePrivate = getPrivateKey(PRIVATE_KEY);
        Cipher ci = Cipher.getInstance(ALGORITHM);
        ci.init(Cipher.DECRYPT_MODE,generatePrivate);
        byte[] bytes = Base64.getDecoder().decode(data);
        int inputLen = bytes.length;
        int offLen = 0;
        int i = 0;
        try(ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()){
            while(inputLen - offLen > 0){
                byte[] cache;
                if(inputLen - offLen > 128){
                    cache = ci.doFinal(bytes,offLen,128);
                }else{
                    cache = ci.doFinal(bytes,offLen,inputLen - offLen);
                }
                byteArrayOutputStream.write(cache);
                i++;
                offLen = 128 * i;
            }
            byteArrayOutputStream.close();
            byte[] byteArray = byteArrayOutputStream.toByteArray();
            return new String(byteArray);
        }
    }

    public static void main(String[] args) throws Exception {
      /*  PrivateKey admin = getPrivateKey("admin");
        System.out.println(admin);*/
        String str = "{\"applyNo\":\"123\"}";
        String s = encryptByPublicKey(str);
        System.out.println(s);
        System.out.println(decryptByPrivateKey(s));
        String s1 = "U3Rlrk+/ypzSnpz1jeehFTPlJaScaAecdsjQ8RBGQuyYTX5deaZzWVAiJ4xaFLM/9zSvDvsatePPVhC94DEItTFNS0uO69X+8VfYMZhuFbQVxcbqsMwzrz/prq7ziNCoSrdDbL1f+v0x0rBYKT9rKVWJLBAbH5jO74l6Y9WJf=";

        System.out.println(decryptByPrivateKey(s1));
    }
}
